define(
	['misc/tools', 'conf/main', 'lib/input', 'core/scene', 'lib/ajax', 'lib/fastclick', 'lib/fps', 'lib/IIG'], 
	function(Tools, Conf, Input, Scene, Ajax, Fastclick, Fps, IIG) {

		var Boilerplate = function() {}

		Boilerplate.prototype = {
			getHelp: function() {
				log("### Your HTML5 canvas boilerplate is now running");
				log("  - Declare 'core/boilerplate' dependency in your modules to access Boilerplate");
				log("  - Enter MyObject.help() to get information about it")
			},
			init: function(Controller) {

				this.getHelp();

				// Initialize default configuration (conf/main.js)
				this.conf = Conf;

				// Initialize Scene
				this.scene = new Scene(Conf.scene);
				// Initialize inputs with canvas as target
				this.input = new Input();

				// Initialize controller
				this.controller = new Controller({parent : this});

				this.controller.init();
				this.input.init({target:this.scene.canvas,controller:this.controller});

				// Get a reference to ajax
				this.ajax = new Ajax();

				if(this.conf.fps === true) {
					this.fps = new FPSMeter({top:"auto",bottom:"0px",theme:"transparent",graph:1,decimals:0});
				}

				this.fastclick = Fastclick.attach(document.body);

				// Initialize images
				this.images = new IIG.ImageManager({
					path : this.conf.images.path
				});

				for(var i = 0, c = this.conf.images.files.length; i < c; i++) {
					this.images.add(this.conf.images.files[i]);
				}

				this.images.loadAll();

				this.images.animation = IIG.Animation;

				this.run();
			},
			run: function() {
				// Reinitialize debug console
				$('#debug').childNodes[1].innerHTML = "";

				// Execute game loop only if game is running 
				if(this.controller.stop == false) {
					// Update game controller
					this.controller.update();
					this.controller.render();
				
					// Listen to input events
					this.input.listen();
					this.images.update();
					this.scene.setOrigin();

					if(this.scene.buffer !== undefined) {
						this.scene.realctx.drawImage(this.scene.buffer, 0, 0, this.scene.width * this.scene.coef, this.scene.height * this.scene.coef);
					}
				} else if(typeof this.controller.MenuManager !== "undefined") {
					this.controller.MenuManager.update();
				}

				if(this.fps !== undefined) {
					this.fps.tick();
				}

				// Call game loop again
				requestAnimationFrame(this.run.bind(this));
			},
			setStop: function(stop) {
				// Stop/start controller
				this.controller.stop = stop;
				// If start controller
				if(stop === false) {
					// Relaunch game loop
					this.run();
					this.fastclick.destroy();
				} else {
					this.input.trigger('stop');
					this.fastclick = Fastclick.attach(document.body);
				}
			},
			setPause: function(pause) {
				// Pause/resume controller
				this.controller.pause = pause;
				this.setStop(pause);

				this.controller.MenuManager.pauseGame();
			},
			getManager : function(Model) {
				if(this.controller[Model+"Manager"] !== undefined) {
					return this.controller[Model+"Manager"];
				} else {
					warn("Game doesn't have "+Model+"Manager.");
				}
			}
		};

		return new Boilerplate();
	}
);